﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic;
using OnePiece.Core.Infrastructure;


namespace OnePiece.Core.Extension.Paging
{
    public static class PageExtension
    {

        public static IQueryable<TSource> Page<TSource>(this IQueryable<TSource> source, ref PageExtensionHelper pageExtensionHelper)
        {
            Guard.IsNotNull(source, "source");
            Guard.IsNotNull(pageExtensionHelper, "pageExtensionHelper");

            IQueryable<TSource> r;

             
            var filter = pageExtensionHelper.Filter;
            if (filter != null)
            {

                var paramIncrement = 0;
                var filterStrings = new List<string>();
                foreach (var rule in filter.Rules)
                {
                    var type = typeof(TSource);
                    var property = type.GetProperty(rule.FilterField);
                    var propertyType = property.PropertyType;

                     
                    //store the key and value in dictionary
                    //the type is nullable so get the underlying type
                    if (propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
                        propertyType = Nullable.GetUnderlyingType(propertyType);

                    var targetType = propertyType.FullName.Replace("System.", string.Empty);
                    var typeCode = (TypeCode)Enum.Parse(typeof(TypeCode), targetType, true);


                    switch (rule.FilterOperator)
                    {
                        case ComparisonOperator.Equal:
                            pageExtensionHelper.FilterParameterValue.Add(Convert.ChangeType(rule.FilterValue, typeCode));
                            filterStrings.Add(string.Format("{0}=@{1}", rule.FilterField, paramIncrement));
                            paramIncrement++;
                            break;
                        case ComparisonOperator.NotEqual:
                            pageExtensionHelper.FilterParameterValue.Add(Convert.ChangeType(rule.FilterValue, typeCode));
                            filterStrings.Add(string.Format("{0}!=@{1}", rule.FilterField, paramIncrement));
                            paramIncrement++;
                            break;
                        case ComparisonOperator.Less:
                            pageExtensionHelper.FilterParameterValue.Add(Convert.ChangeType(rule.FilterValue, typeCode));
                            filterStrings.Add(string.Format("{0}<@{1}", rule.FilterField, paramIncrement));
                            paramIncrement++;
                            break;
                        case ComparisonOperator.LessOrEqual:
                            pageExtensionHelper.FilterParameterValue.Add(Convert.ChangeType(rule.FilterValue, typeCode));
                            filterStrings.Add(string.Format("{0}<=@{1}", rule.FilterField, paramIncrement));
                            paramIncrement++;
                            break;
                        case ComparisonOperator.Greater:
                            pageExtensionHelper.FilterParameterValue.Add(Convert.ChangeType(rule.FilterValue, typeCode));
                            filterStrings.Add(string.Format("{0}>@{1}", rule.FilterField, paramIncrement));
                            paramIncrement++;
                            break;
                        case ComparisonOperator.GreaterOrEqual:
                            pageExtensionHelper.FilterParameterValue.Add(Convert.ChangeType(rule.FilterValue, typeCode));
                            filterStrings.Add(string.Format("{0}>=@{1}", rule.FilterField, paramIncrement));
                            paramIncrement++;
                            break;
                        case ComparisonOperator.StartsWith:
                            filterStrings.Add(string.Format("{0}.StartsWith(\"{1}\")", rule.FilterField, rule.FilterValue));
                            break;
                        case ComparisonOperator.DoesNotStartsWith:
                            filterStrings.Add(string.Format("!{0}.StartsWith(\"{1}\")", rule.FilterField, rule.FilterValue));
                            break;
                        case ComparisonOperator.Contains:
                        case ComparisonOperator.IsIn:
                            filterStrings.Add(string.Format("{0}.Contains(\"{1}\")", rule.FilterField, rule.FilterValue));
                            break;
                        case ComparisonOperator.DoesNotContains:
                        case ComparisonOperator.IsNotIn:
                            filterStrings.Add(string.Format("!{0}.Contains(\"{1}\")", rule.FilterField, rule.FilterValue));
                            break;
                        case ComparisonOperator.EndsWith:
                            filterStrings.Add(string.Format("{0}.EndsWith(\"{1}\")", rule.FilterField, rule.FilterValue));
                            break;
                        case ComparisonOperator.DoesNotEndsWith:
                            filterStrings.Add(string.Format("!{0}.EndsWith(\"{1}\")", rule.FilterField, rule.FilterValue));
                            break;
                    }

                }

                pageExtensionHelper.LinqFilterString = string.Join(string.Format(" {0} ", filter.GroupOn.ToName()), filterStrings.ToArray());
            }



            if (string.IsNullOrEmpty(pageExtensionHelper.LinqFilterString))
            {
                pageExtensionHelper.TotalItems = source.LongCount();
                r = pageExtensionHelper.SortString == string.Empty
                        ? source.Skip((pageExtensionHelper.PageIndex - 1) * pageExtensionHelper.PageSize).Take(pageExtensionHelper.PageSize)
                        : source.OrderBy(pageExtensionHelper.SortString).Skip((pageExtensionHelper.PageIndex - 1) * pageExtensionHelper.PageSize).Take(pageExtensionHelper.PageSize);
            }
            else
            {

                source = source.Where(pageExtensionHelper.LinqFilterString, pageExtensionHelper.FilterParameterValue.ToArray());

                pageExtensionHelper.TotalItems = source.LongCount();
                r = pageExtensionHelper.SortString == string.Empty
                        ? source.Skip((pageExtensionHelper.PageIndex - 1) * pageExtensionHelper.PageSize).Take(pageExtensionHelper.PageSize)
                        : source.OrderBy(pageExtensionHelper.SortString).Skip((pageExtensionHelper.PageIndex - 1) * pageExtensionHelper.PageSize).Take(pageExtensionHelper.PageSize);

            }


            return r;
        }

        public static IQueryable<TSource> Page<TSource>(this IQueryable<TSource> source, int pageIndex, int pageSize, ref PageExtensionHelper helper)
        {
            helper.PageSize = pageSize;
            helper.PageIndex = pageIndex;
            return Page(source, ref helper);
        }

        public static IEnumerable<TSource> Page<TSource>(this IEnumerable<TSource> source, ref PageExtensionHelper pageExtensionHelper)
        {
            Guard.IsNotNull(source, "source");
            Guard.IsNotNull(pageExtensionHelper, "pageExtensionHelper");

            pageExtensionHelper.TotalItems = source.LongCount();
            return source.Skip((pageExtensionHelper.PageIndex - 1) * pageExtensionHelper.PageSize).Take(pageExtensionHelper.PageSize);

        }
    }



}